package com.example.xinli.service.serviceImpl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.slf4j.Logger;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.xinli.dao.ExUserMapper;
import com.example.xinli.domain.dto.ExUserDto;
import com.example.xinli.domain.dto.LoginPhoneResDto;
import com.example.xinli.domain.dto.WxAccessTokenDto;
import com.example.xinli.domain.dto.WxPhoneResultDto;
import com.example.xinli.domain.entity.ExUser;
import com.example.xinli.domain.entity.Record;
import com.example.xinli.domain.entity.User;
import com.example.xinli.dao.RecordMapper;
import com.example.xinli.dao.UserMapper;
import com.example.xinli.domain.vo.*;
import com.example.xinli.pojo.WeixinLoginResult;
import com.example.xinli.service.IUserService;
import com.example.xinli.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.example.xinli.common.RedisConstants.*;
import static com.example.xinli.common.UserConstants.*;


@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RecordMapper recordMapper;

    @Autowired
    private ExUserMapper exUserMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisTemplate redisTemplate;


    final String SECRET = "840d0f06109cb579bb2ad593dfeb8092";
    final String APPID = "wx24b75d08aed0c537";
    final String GRANT_TYPE = "authorization_code";

    @Override
    @Transactional
    public ResponseBean doLogin(LoginVo loginVo) {
        String CODE = loginVo.getCode();

        // 通过code换取openid和session_key
        String weixinUrl = "https://api.weixin.qq.com/sns/jscode2session?" +
                "appid=" + APPID +
                "&secret=" + SECRET +
                "&js_code=" + CODE +
                "&grant_type=" + GRANT_TYPE;

        ResponseEntity<String> responseEntity = restTemplate.getForEntity(weixinUrl, String.class);
        WeixinLoginResult resultObj = JSON.parseObject(responseEntity.getBody(), WeixinLoginResult.class);

        if (resultObj != null) {
            // 生成 token
            String token = TokenUtil.sign(resultObj.getSessionId(), resultObj.getOpenId());

            // 从数据库查找用户
            User user = userMapper.selectById(resultObj.getOpenId());
            if(user == null) {
                String userId= resultObj.getOpenId();
                // 第一次登录 该用户不存在 默认对照组，id为1
                User newUser = new User(resultObj.getOpenId(), DEFAULT_USER_NAME, DEFAULT_PHONE, 0, DEFAULT_AVATAR_URL,"user",2);
                // User newUser = new User(resultObj.getOpenId(), DEFAULT_USER_NAME, DEFAULT_PHONE, 8, DEFAULT_AVATAR_URL,"user",1);
                userMapper.insert(newUser);
                // 登陆成功 redis 保存token对应的用户信息 1天后过期
                redisTemplate.opsForValue().set("user:" + token, newUser);
                // redisTemplate.expire("user:" + token, 1, TimeUnit.DAYS);
            } else {
                QueryWrapper<ExUser> exUserQueryWrapper = new QueryWrapper<>();
                exUserQueryWrapper.eq("phone", user.getPhone());
                ExUser exUserList = exUserMapper.selectOne(exUserQueryWrapper);
                if (exUserList != null) {
                    user.setGroupId(exUserList.getGroupId());
                    QueryWrapper<User> userUpdateWrapper = new QueryWrapper<>();
                    userUpdateWrapper.eq("user_id", user.getUserId());
                    log.info(user.toString());
                    userMapper.update(user, userUpdateWrapper);
                }
                // redis 保存token对应的用户信息 1天后过期
                redisTemplate.opsForValue().set("user:" + token, user);
                // redisTemplate.expire("user:" + token, 1, TimeUnit.DAYS);
            }
            log.info(token);
            return ResponseBean.success(token);
        } else {
            return ResponseBean.error(ResponseBeanEnum.SESSION_ERROR);
        }

    }

    @Override
    @Transactional
    public ResponseBean getPhoneNumber(WxGetPhoneVo phoneVo) {
        LoginPhoneResDto loginPhoneResDto = new LoginPhoneResDto();
//        先从redis里面找
        String accessToken = (String) redisTemplate.opsForValue().get(WX_ACCESS_TOKEN);

        if (accessToken == null || accessToken.isEmpty()) {
            // 如果Redis中不存在access_token，或者已过期，发送请求获取新的access_token
            String accessUrl = "https://api.weixin.qq.com/cgi-bin/token" +
                    "?grant_type=client_credential" +
                    "&appid=" + APPID +
                    "&secret=" + SECRET;
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(accessUrl, String.class);
            WxAccessTokenDto resultObj = JSON.parseObject(responseEntity.getBody(), WxAccessTokenDto.class);
            accessToken = resultObj.getAccessToken();

            // 将获取到的access_token存储到Redis中，并设置过期时间，假设有效期为7200秒（2小时），通常要比实际时间略短一点，以防止token失效
            redisTemplate.opsForValue().set(WX_ACCESS_TOKEN, accessToken, resultObj.getExpiresIn(), TimeUnit.SECONDS);
        }
        
//        如果没查到手机号码，就去微信服务器查
        User user = userMapper.selectById(phoneVo.getOpenid());
        loginPhoneResDto.setFirstLogin(false);

        if (user != null) {
            if (user.getPhone().equals(DEFAULT_PHONE)) {
                loginPhoneResDto.setFirstLogin(true);

                // 说明用户没有手机号码
                log.info("执行到请求手机号接口");
                String decryptUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber" +
                        "?access_token=" + accessToken ;

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);

                // 构建请求体
                Map<String, Object> requestBody = new HashMap<>();
                log.info("code", phoneVo.getCode());
                requestBody.put("code", phoneVo.getCode()); // yourDataObject是你要发送的数据，可以是String、Map或者其他对象

                // 将请求头和请求体组合成HttpEntity
                HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

                // 发送POST请求
                ResponseEntity<String> responseEntity = restTemplate.postForEntity(decryptUrl, requestEntity, String.class);
                WxPhoneResultDto res = JSON.parseObject(responseEntity.getBody(), WxPhoneResultDto.class);

                user.setPhone(res.getPhoneInfo().getPhoneNumber());
                userMapper.updateById(user);

                //查到手机号之后，更新组别
                List<ExUser> exUserList = exUserMapper.selectList(new QueryWrapper<ExUser>().eq("phone", user.getPhone()));
                ExUser exUser = exUserList.isEmpty() ? null : exUserList.get(exUserList.size() - 1);
                if(exUser != null){
                    user.setGroupId(exUser.getGroupId());

                    if(exUser.getGroupId()== 1) {
                        user.setCurrProgress(8);
                    }
                    QueryWrapper<User> userUpdateWrapper = new QueryWrapper<>();
                    userUpdateWrapper.eq("user_id", user.getUserId());
                    userMapper.update(user, userUpdateWrapper);
//                    log.info("执行这个");
                }
                loginPhoneResDto.setGroupId(user.getGroupId());

            } else {
                loginPhoneResDto.setGroupId(user.getGroupId());
            }
        }
        return ResponseBean.success(loginPhoneResDto);

    }


    @Override
    public ResponseBean doLogout(String token) {
        Boolean res = redisTemplate.delete("user:" + token);
        if (Boolean.TRUE.equals(res)) {
            return ResponseBean.success();
        }
        return ResponseBean.error(ResponseBeanEnum.ERROR);
    }

    @Override
    public ResponseBean getUserInfo(String token) {
        String openId = TokenUtil.getId(token);
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("user_id", openId);
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            return ResponseBean.success(user);
        } else {
            return ResponseBean.error(ResponseBeanEnum.ERROR);
        }
//        Object user = redisTemplate.opsForValue().get("user:" + token);
//        if (user != null) {
//            return ResponseBean.success(user);
//        } else {
//            return ResponseBean.error(ResponseBeanEnum.ERROR);
//        }
    }

    @Override
    public ResponseBean getUserRecords(String token) {
        String openId = TokenUtil.getId(token);
        QueryWrapper<Record> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", openId);

        List<Record> recordList = recordMapper.selectList(queryWrapper);
        return ResponseBean.success(recordList);
    }

//    根据userId返回phone
    public String getUserPhoneById(String id){
        User user = userMapper.selectById(id);
        return user.getPhone();

    }

    public Map<String, String> getUserPhonesByIds(Set<String> userIds) {
        // 批量查询用户信息
        List<User> users = userMapper.selectBatchIds(userIds);

        // 转换为 Map
        Map<String, String> userPhones = users.stream()
                .collect(Collectors.toMap(User::getUserId, User::getPhone));

        return userPhones;
    }

    public Map<String, String> getUserExidByIds(Set<String> userIds) {

        Map<String, String> userPhones=getUserPhonesByIds(userIds);




        // 根据 userPhones 的手机号获取 ExUser 列表
        List<ExUser> exusers = exUserMapper.selectList(new LambdaQueryWrapper<ExUser>()
                .in(ExUser::getPhone, userPhones.values()));

//        log.info(exusers.toString());

// 将 ExUser 的手机号和 userId 映射到 Map
        Map<String, String> userIdMap = exusers.stream()
                .collect(Collectors.toMap(ExUser::getPhone, ExUser::getUserId));

//        log.info(userIdMap.toString());
// 根据 userPhones 的手机号构建最终的映射
//        Map<String, String> userExids = new HashMap<>();
//        for (String phone : userPhones.values()) {
//            userExids.put(userPhones.get(phone), userIdMap.get(phone));
//        }

        return userIdMap;
    }


    public ResponseBean getAllUserInfo(){
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

        List<User> userList = userMapper.selectList(null);

        List<String> openIdList = userList.stream()
                .map(User::getUserId)
                .collect(Collectors.toList());

        List<String> phoneList = userList.stream()
                .map(User::getPhone)
                .collect(Collectors.toList());

        // 根据 phone 列表查询 ExUser
        List<ExUser> exUserList = exUserMapper.selectList(
                new QueryWrapper<ExUser>().in("phone", phoneList)
        );

        // 根据 openIdList 查询 Record 列表
        List<Record> recordList = recordMapper.selectList(
                new QueryWrapper<Record>().in("user_id", openIdList)
        );
        String endtime;

        // 根据 openId 对 recordList 进行分组，并获取每组的最后一条记录的 endtime
        Map<String, String> lastEndtimeByOpenId = recordList.stream()
                .collect(Collectors.groupingBy(
                        Record::getUserId, // 按 openId 分组
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                records -> records.stream()
                                        .filter(record -> record.getEndTime() != null && !record.getEndTime().isEmpty()) // 过滤掉 endtime 为空的记录
                                        .max(Comparator.comparing(record -> LocalDateTime.parse(record.getEndTime(), dateTimeFormatter))) // 比较解析后的 LocalDateTime
                                        .map(Record::getEndTime) // 提取原始字符串 endtime 字段
                                        .orElse(null) // 如果没有记录则返回 null如果没有记录则返回 null
                        )
                ));

// 输出每个 openId 的最后一条记录的 endtime
//        lastEndtimeByOpenId.forEach((openId, endtime) -> {
//            System.out.println("OpenId: " + openId + ", 最后一条记录的 endtime: " + endtime);
//        });

        // 创建一个 Map，方便根据 phone 快速查找 ExUser 的 userId
        Map<String, String> phoneToUserIdMap = exUserList.stream()
                .collect(Collectors.toMap(ExUser::getPhone, ExUser::getUserId));

        // 构建 AdminUserVO 列表
        List<AdminUserVO> adminUserVOS = userList.stream().map(user -> {
            AdminUserVO adminUserVO = new AdminUserVO();

            adminUserVO.setOpenid(user.getUserId());

            adminUserVO.setUsername(user.getUsername());

            adminUserVO.setPhone(user.getPhone());
            adminUserVO.setCurrProgress(user.getCurrProgress());


            //设置已解锁单元，要去redis找有没有值，判断有没有解锁
            if(redisTemplate.opsForValue().get("inter:" + user.getUserId())!=null) {
                adminUserVO.setHasFinished(user.getCurrProgress() - 1);
            }
            else{
                adminUserVO.setHasFinished(user.getCurrProgress());
            }

            adminUserVO.setGroupId(user.getGroupId());

            adminUserVO.setFinishTime(lastEndtimeByOpenId.get(user.getUserId()));

            // 根据 phone 从 Map 中获取 userId
            String userId = phoneToUserIdMap.get(user.getPhone());
            adminUserVO.setUserId(userId);

//            log.info(adminUserVO.toString());

            return adminUserVO;
        }).collect(Collectors.toList());

        return ResponseBean.success(adminUserVOS);
    }

    public ResponseBean getPreUserInfo(){
        List<ExUser> userList = exUserMapper.selectList(null);
        return ResponseBean.success(userList);
    }

    public ResponseBean setUserAvatar(String id,String avatarURL){
        User user=userMapper.selectById(id);
        user.setAvatar(avatarURL);
        userMapper.updateById(user);
        return ResponseBean.success();
    }

    public ResponseBean setUserName(String id,String name){
        User user=userMapper.selectById(id);
        user.setUsername(name);
        userMapper.updateById(user);
        return ResponseBean.success();
    }

    public ResponseBean evalRole(String key){
        String right=(String)redisTemplate.opsForValue().get(LOGIN_ROLE_KEY);
        log.info(right);
        log.info(key);
        if(key.equals(right)){
            return ResponseBean.success(1);
        }else{
            return ResponseBean.success(0);
        }
    }

    public ResponseBean setevalKey(String key){
        redisTemplate.opsForValue().set(LOGIN_ROLE_KEY,key);
        return ResponseBean.success();
    }

    public ResponseBean setRole(String id,String role){
        User user=userMapper.selectById(id);
        user.setRole(role);
        userMapper.updateById(user);
        return ResponseBean.success();
    }

    public ResponseBean getAccessToken(){
        String accessToken = (String) redisTemplate.opsForValue().get(WX_ACCESS_TOKEN);

        if (accessToken == null || accessToken.isEmpty()) {
            // 如果Redis中不存在access_token，或者已过期，发送请求获取新的access_token
            String accessUrl = "https://api.weixin.qq.com/cgi-bin/token" +
                    "?grant_type=client_credential" +
                    "&appid=" + APPID +
                    "&secret=" + SECRET;
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(accessUrl, String.class);
            WxAccessTokenDto resultObj = JSON.parseObject(responseEntity.getBody(), WxAccessTokenDto.class);
            accessToken = resultObj.getAccessToken();

            // 将获取到的access_token存储到Redis中，并设置过期时间，假设有效期为7200秒（2小时），通常要比实际时间略短一点，以防止token失效
            redisTemplate.opsForValue().set(WX_ACCESS_TOKEN, accessToken, resultObj.getExpiresIn(), TimeUnit.SECONDS);
        }
        return ResponseBean.success(accessToken);
    }

    public ResponseBean setUserGroup(ExUserDto exUserDto){
        ExUser exUser = new ExUser();
        exUser.setPhone(exUserDto.getPhone());
        exUser.setGroupId(exUserDto.getGroupId());
        exUser.setUserId(exUserDto.getUserId());
        exUserMapper.insert(exUser);
        return ResponseBean.success();
    }

    public String getUserIdByOpenId(String openId){

        String phone=userMapper.selectById(openId).getPhone();

        ExUser exUser = exUserMapper.selectOne(new QueryWrapper<ExUser>().eq("phone", phone));

        String id=exUser.getUserId();

        if(id==null){
            id="000";
        }
        return id;


    }
}

